package com.tengju.bff.interfaces.covercharge.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.tengju.bff.interfaces.covercharge.constant.CoverChargeErrorCode;
import com.tengju.bff.interfaces.covercharge.dto.*;
import com.tengju.bff.interfaces.covercharge.enums.OperateBizTypeEnum;
import com.tengju.bff.interfaces.covercharge.constant.OperateStatusEnum;
import com.tengju.bff.interfaces.covercharge.entity.po.ServiceOperateDetail;
import com.tengju.bff.interfaces.covercharge.entity.po.ServiceOperateRecord;
import com.tengju.bff.interfaces.covercharge.enums.ServiceAccountTypeEnum;
import com.tengju.bff.interfaces.covercharge.mapper.ServiceOperateDetailMapper;
import com.tengju.bff.interfaces.covercharge.mapper.ServiceOperateRecordMapper;
import com.tengju.bff.interfaces.covercharge.service.IProfitSettleService;
import com.tengju.bff.interfaces.covercharge.util.BeanMapperUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author liang_shi
 * @date 2020/8/4 11:46
 * @description 收益结算服务
 */
@Slf4j
@Service
public class ProfitSettleServiceImpl implements IProfitSettleService {

    @Autowired
    private ServiceOperateRecordMapper operateRecordMapper;

    @Autowired
    private ServiceOperateDetailMapper operateDetailMapper;

    @Autowired
    private ServiceAccountServiceImpl accountService;


    @Override
    public ServiceDealResDTO querySettleResultByUniqueId(String type, String uniqueId) {
        ServiceOperateRecord operateLog = new ServiceOperateRecord();
        operateLog.setBizType(type);
        operateLog.setUniqueId(uniqueId);
        ServiceOperateRecord sol = operateRecordMapper.selectOne(new QueryWrapper<>(operateLog));
        if (Objects.isNull(sol)) {
            return null;
        }
        ServiceDealResDTO dealResDTO = new ServiceDealResDTO();
        dealResDTO.setUniqueId(uniqueId);
        dealResDTO.setCode(sol.getStatus());
        dealResDTO.setMsg(sol.getMessage());
        if (OperateStatusEnum.PROCESSING.getStatus().equals(sol.getStatus()) || OperateStatusEnum.SUCCESS.getStatus().equals(sol.getStatus())) {
            dealResDTO.setBizNo(OperateBizTypeEnum.PROFIT_SETTLE);
            return dealResDTO;
        }
        //失败情况，获取明细
        ServiceOperateDetail operateDetail = new ServiceOperateDetail();
        operateDetail.setUniqueId(uniqueId);
        QueryWrapper<ServiceOperateDetail> queryWrapper = new QueryWrapper<>(operateDetail);
        queryWrapper.orderByDesc("id");
        List<ServiceOperateDetail> operateDetails = operateDetailMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(operateDetails)) {
            return dealResDTO;
        }
        OperateBizTypeEnum bizNoEnum = OperateBizTypeEnum.PROFIT_SETTLE;
        for (ServiceOperateDetail opDetail : operateDetails) {
            OperateBizTypeEnum bizTypeEnum = OperateBizTypeEnum.getInstance(opDetail.getBizNode());
            if (Objects.isNull(bizTypeEnum)) {
                continue;
            }
            switch (bizTypeEnum) {
                case PROFIT_SETTLE_NODE_1:
                    if (OperateStatusEnum.FAILED.getStatus().equals(opDetail.getStatus()) || OperateStatusEnum.PROCESSING.getStatus().equals(opDetail.getStatus())) {
                        bizNoEnum = OperateBizTypeEnum.PROFIT_SETTLE_NODE_1;
                        break;
                    }
                case PROFIT_SETTLE_NODE_2:
                    if (OperateStatusEnum.FAILED.getStatus().equals(opDetail.getStatus()) || OperateStatusEnum.PROCESSING.getStatus().equals(opDetail.getStatus())) {
                        bizNoEnum = OperateBizTypeEnum.PROFIT_SETTLE_NODE_2;
                        break;
                    }
                default:
                    break;
            }
            break;
        }
        dealResDTO.setBizNo(bizNoEnum);
        return dealResDTO;
    }

    @Override
    public void createOperateRecord(String type, String uniqueId) {
        ServiceOperateRecord operateRecord = new ServiceOperateRecord();
        operateRecord.setBizType(type);
        operateRecord.setUniqueId(uniqueId);
        operateRecord.setStatus(OperateStatusEnum.PROCESSING.getStatus());
        operateRecord.setCreateTime(LocalDateTime.now());
        operateRecord.setUpdateTime(LocalDateTime.now());
        int num = operateRecordMapper.insert(operateRecord);
        Assert.isTrue(num == 1, "创建操作记录失败");
    }

    @Override
    public void modifyOperateRecord(String uniqueId, Integer status, String message) {
        ServiceOperateRecord operateRecord = new ServiceOperateRecord();
        operateRecord.setStatus(status);
        operateRecord.setMessage(message);
        operateRecord.setUpdateTime(LocalDateTime.now());

        ServiceOperateRecord updateSor = new ServiceOperateRecord();
        updateSor.setUniqueId(uniqueId);
        int num = operateRecordMapper.update(operateRecord, new UpdateWrapper<>(updateSor));
        Assert.isTrue(num == 1, "更新操作记录失败");
    }


    @Override
    public boolean dealAccountCoreSettle(String uniqueId, ChangeBalanceReqDTO balanceReqDTO, ServiceDealResDTO dealResDTO) {
        boolean dealResult = Boolean.FALSE;
        //操作货款账户
        if (Objects.isNull(balanceReqDTO) || CollectionUtils.isEmpty(balanceReqDTO.getOrderReqs())) {
            log.info("处理账户核心结算结束,无数据,uniqueId:{}", uniqueId);
            return Boolean.TRUE;
        }
        log.info("处理账户核心结算开始,入参,uniqueId:{},balanceReqDTO:{}", uniqueId, balanceReqDTO);
        Integer detailId = -1;
        try {
            OperateBizTypeEnum bizNode = OperateBizTypeEnum.PROFIT_SETTLE_NODE_1;
            if (checkOpIsSuc(uniqueId, bizNode.getType())) {
                log.info("处理账户核心结算结束,已处理,uniqueId:{}", uniqueId);
                return Boolean.TRUE;
            }
            //落明细表
            String bizId = IdWorker.getIdStr();
            dealResDTO.setBizId(bizId);
            dealResDTO.setBizNo(bizNode);
            detailId = createOperateDetail(uniqueId, bizNode.getType(), bizId);
//            ChangeBalance changeBalance = BeanMapperUtils.map(balanceReqDTO, ChangeBalance.class);
//            JsonResult<AccountBalanceMQMessageVO> messageResult = accountFlowProvider.changeBalance(changeBalance);
//            //情况判断处理
//            if (!Objects.isNull(messageResult) && !Objects.isNull(messageResult.getData())
//                    && (messageResult.getData().getResultCode() == 0)) {
//                modifyOperateDetail(detailId, OperateStatusEnum.SUCCESS.getStatus(), null);
//                dealResult = Boolean.TRUE;
//            } else {
//                String msg = Objects.isNull(messageResult.getData()) ? messageResult.getMsg() : messageResult.getData().getMsg();
//                dealResDTO.setCode(OperateStatusEnum.FAILED.getStatus());
//                dealResDTO.setMsg(msg);
//                modifyOperateDetail(detailId, OperateStatusEnum.FAILED.getStatus(), msg);
//            }
            log.info("处理账户核心结算结束,uniqueId:{}", uniqueId);
        } catch (Exception e) {
            log.error("处理账户核心结算异常:", e);
            dealResDTO.setCode(OperateStatusEnum.FAILED.getStatus());
            dealResDTO.setMsg(CoverChargeErrorCode.ACC_BUSINESS_EXCEPTION.getMsg());
            modifyOperateDetail(detailId, OperateStatusEnum.FAILED.getStatus(), CoverChargeErrorCode.ACC_BUSINESS_EXCEPTION.getMsg());
        }
        return dealResult;
    }

    @Override
    public boolean dealServiceCoreSettle(String uniqueId, ChangeProfitDTO changeProfit, ServiceDealResDTO dealResDTO) {
        //操作货款账户
        if (Objects.isNull(changeProfit)) {
            log.info("处理服务费账户结算结束,无数据,uniqueId:{}", uniqueId);
            return Boolean.TRUE;
        }
        log.info("处理服务费账户结算开始,入参,uniqueId:{},changeProfit:{}", uniqueId, changeProfit);
        Integer detailId = -1;
        try {
            String bizNode = OperateBizTypeEnum.PROFIT_SETTLE_NODE_2.getType();
            if (checkOpIsSuc(uniqueId, bizNode)) {
                log.info("处理服务费账户结算结束,已处理,uniqueId:{}", uniqueId);
                return Boolean.TRUE;
            }
            //落明细表
            String bizId = IdWorker.getIdStr();
            dealResDTO.setBizId(bizId);
            detailId = createOperateDetail(uniqueId, bizNode, bizId);
            boolean result = accountService.dealServiceAccountAndDetail(changeProfit);
            modifyOperateDetail(detailId, OperateStatusEnum.SUCCESS.getStatus(), null);
            log.info("处理服务费账户结算结束,uniqueId:{}", uniqueId);
            return result;
        } catch (Exception e) {
            log.error("处理服务费账户结算异常:", e);
            dealResDTO.setCode(OperateStatusEnum.FAILED.getStatus());
            dealResDTO.setMsg(CoverChargeErrorCode.SER_BUSINESS_EXCEPTION.getMsg());
            modifyOperateDetail(detailId, OperateStatusEnum.FAILED.getStatus(), CoverChargeErrorCode.SER_BUSINESS_EXCEPTION.getMsg());
            return Boolean.FALSE;
        }
    }

    @Override
    public boolean dealServiceCoreSettleByDetail(String uniqueId, ChangeProfitDetailDTO changeProfit, ServiceDealResDTO dealResDTO) {
        //操作货款账户
        if (Objects.isNull(changeProfit)) {
            log.info("根据明细处理服务费账户结算结束,无数据,uniqueId:{}", uniqueId);
            return Boolean.TRUE;
        }
        log.info("根据明细处理服务费账户结算开始,入参,uniqueId:{},changeProfit:{}", uniqueId, changeProfit);
        Integer detailId = -1;
        try {
            OperateBizTypeEnum bizNode = OperateBizTypeEnum.PROFIT_SETTLE_NODE_2;
            if (checkOpIsSuc(uniqueId, bizNode.getType())) {
                log.info("根据明细处理服务费账户结算结束,已处理,uniqueId:{}", uniqueId);
                return Boolean.TRUE;
            }
            //落明细表
            String bizId = IdWorker.getIdStr();
            dealResDTO.setBizId(bizId);
            dealResDTO.setBizNo(bizNode);
            detailId = createOperateDetail(uniqueId, bizNode.getType(), bizId);
            accountService.dealServiceAccountByDetail(uniqueId,changeProfit);
            modifyOperateDetail(detailId, OperateStatusEnum.SUCCESS.getStatus(), null);
            log.info("根据明细处理服务费账户结算结束,uniqueId:{}", uniqueId);
            return Boolean.TRUE;
        } catch (Exception e) {
            log.error("根据明细处理服务费账户结算异常:uniqueId：{}", uniqueId, e);
            dealResDTO.setCode(OperateStatusEnum.FAILED.getStatus());
            dealResDTO.setMsg(CoverChargeErrorCode.SER_BUSINESS_EXCEPTION.getMsg());
            modifyOperateDetail(detailId, OperateStatusEnum.FAILED.getStatus(), CoverChargeErrorCode.SER_BUSINESS_EXCEPTION.getMsg());
            return Boolean.FALSE;
        }

    }

    /**
     * 创建
     *
     * @param uniqueId 幂等Id
     * @param nodeType 类型
     * @param bizId    业务流水
     * @return 主键
     */
    private Integer createOperateDetail(String uniqueId, String nodeType, String bizId) {
        ServiceOperateDetail detail = new ServiceOperateDetail();
        detail.setUniqueId(uniqueId);
        detail.setBizId(bizId);
        detail.setBizNode(nodeType);
        detail.setStatus(OperateStatusEnum.PROCESSING.getStatus());
        detail.setCreateTime(LocalDateTime.now());
        detail.setUpdateTime(LocalDateTime.now());
        int num = operateDetailMapper.insert(detail);
        Assert.isTrue(num == 1, "创建操作明细记录失败");
        return detail.getId();
    }

    /**
     * 修改
     *
     * @param detailId 详情Id
     * @param status   状态
     * @param message  信息
     */
    private void modifyOperateDetail(Integer detailId, Integer status, String message) {
        ServiceOperateDetail detail = new ServiceOperateDetail();
        detail.setId(detailId);
        detail.setStatus(status);
        detail.setMessage(message);
        detail.setUpdateTime(LocalDateTime.now());
        int num = operateDetailMapper.updateById(detail);
        Assert.isTrue(num == 1, "更新操作明细记录失败");
    }

    /**
     * 校验是否处理成功
     *
     * @param uniqueId 幂等Id
     * @param bizNode  节点
     * @return 结果
     */
    private boolean checkOpIsSuc(String uniqueId, String bizNode) {
        boolean checkResult = Boolean.FALSE;
        ServiceOperateDetail sod = new ServiceOperateDetail();
        sod.setUniqueId(uniqueId);
        sod.setBizNode(bizNode);
        List<ServiceOperateDetail> sodList = operateDetailMapper.selectList(new QueryWrapper<>(sod));
        if (!CollectionUtils.isEmpty(sodList)) {
            long count = sodList.stream().filter(info -> OperateStatusEnum.SUCCESS.getStatus().equals(info.getStatus())).count();
            if (count > 0) {
                checkResult = Boolean.TRUE;
            }
        }
        return checkResult;
    }

}
